{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2c000cd3-4871-4494-b717-db7190ccdbfe",
   "metadata": {},
   "source": [
    "# Tests for Husky PLL phase adjustment.\n",
    "\n",
    "Checks whether the actual relative phase between target and ADC clocks is correct.\n",
    "\n",
    "While the part 1 notebook covers related things, it doesn't care about what the phase actually **is**. This notebook does. Covers issue [501](https://github.com/newaetech/chipwhisperer/issues/501).\n",
    "\n",
    "Some occasional failures are to be expected.\n",
    "\n",
    "Should be run whenever changes are made to `ChipWhispererHuskyClocks.py`.\n",
    "\n",
    "Could be a `pytest` script, however the ability to plot the clocks and visualize can be really useful when debugging."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "437412e7-a94c-4b87-8c09-d56cb408638b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c6f255df-c339-4428-9922-b3bb01baa05d",
   "metadata": {},
   "outputs": [],
   "source": [
    "scope = cw.scope()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a42bc734-b054-4e60-aa6f-202b7e7fda13",
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.default_setup()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d7196f4-d863-4d49-a6ae-a0b7961e2080",
   "metadata": {},
   "source": [
    "# There are two cases to cover:\n",
    "1. `EXTCLK = True`: target-supplied clock, from a CW305. Could be adapted to use a different target, but we need to be able to set its clock over a wide range.\n",
    "2. `EXTCLLK = False`: no target needed; PLL uses 12 MHz XTAL reference."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c549df54-2cfb-48b8-ab92-ee9089c5bbe9",
   "metadata": {},
   "outputs": [],
   "source": [
    "EXTCLK = True\n",
    "#EXTCLK = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29491931-9140-4b10-b964-fe43230cac86",
   "metadata": {},
   "outputs": [],
   "source": [
    "if EXTCLK:\n",
    "    # setting PLL won't work without a bitfile?\n",
    "    target = cw.target(scope, cw.targets.CW305, fpga_id='100t')\n",
    "    target.pll.pll_enable_set(True)\n",
    "    target.pll.pll_outenable_set(False, 0)\n",
    "    target.pll.pll_outenable_set(True, 1)\n",
    "    target.pll.pll_outenable_set(False, 2)\n",
    "    target.pll.pll_outfreq_set(10e6, 1)\n",
    "    MAXCLOCK = 167e6\n",
    "    scope.clock.clkgen_freq = 10e6\n",
    "    scope.clock.clkgen_src = 'extclk'\n",
    "else:\n",
    "    MAXCLOCK = 200e6\n",
    "    target = None\n",
    "    scope.clock.clkgen_src = 'system'\n",
    "    scope.clock.clkgen_freq = 7.37e6\n",
    "\n",
    "OVERSAMP = 20\n",
    "scope.LA.enabled = True\n",
    "if EXTCLK:\n",
    "    scope.LA.clk_source = 'target'\n",
    "else:\n",
    "    scope.LA.clk_source = 'pll'\n",
    "scope.LA.clkgen_enabled = False\n",
    "scope.LA.oversampling_factor = OVERSAMP\n",
    "scope.LA.clkgen_enabled = True\n",
    "scope.LA.capture_group = 'CW 20-pin'\n",
    "scope.LA.capture_depth = 200 \n",
    "assert scope.LA.locked"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "447c272b-b491-49a5-a8b1-36e9ea084be3",
   "metadata": {},
   "source": [
    "When `EXTCLK = True`, there would be a bunch of `scope_logger.errors()` due to clock/mul settings that can't be achieved; this silences them so that the output isn't cluttered.\n",
    "\n",
    "For the same reason, we mute warnings.\n",
    "\n",
    "**If debugging, unset `scope.clock._quiet` to see all errors, and turn warnings back on!**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ff3c59e1-7c10-4c01-b3c4-9636e3bce663",
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.scope_logger.setLevel(cw.logging.ERROR)\n",
    "#cw.scope_logger.setLevel(cw.logging.WARNING)\n",
    "\n",
    "if EXTCLK:\n",
    "    scope.clock._quiet = True\n",
    "else:\n",
    "    scope.clock._quiet = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb635cc5-d3ee-45a1-a473-daea3f7c8649",
   "metadata": {},
   "outputs": [],
   "source": [
    "def setup(freq, mul, phase_raw):\n",
    "    global all_settings\n",
    "    if EXTCLK:\n",
    "        target.pll.pll_outfreq_set(freq, 1)\n",
    "    scope.clock.adc_mul = mul\n",
    "    scope.clock.clkgen_freq = freq\n",
    "    scope.clock.adc_phase_raw = phase_raw\n",
    "    assert scope.clock.pll.pll_locked\n",
    "    setting = {}\n",
    "    setting['freq'] = freq\n",
    "    setting['mul'] = mul\n",
    "    setting['phase_raw'] = phase_raw\n",
    "    setting['pll_settings'] = str(scope.clock.pll)\n",
    "    setting['params'] = list(scope.clock.pll.parameters)\n",
    "    all_settings.append(setting)\n",
    "\n",
    "def set_oversamp(oversamp):\n",
    "    scope.LA.clkgen_enabled = False\n",
    "    scope.LA.oversampling_factor = oversamp\n",
    "    scope.LA.clkgen_enabled = True\n",
    "    assert scope.LA.locked\n",
    "\n",
    "def find0to1trans(data):\n",
    "    pattern = [0,1]\n",
    "    return [i for i in range(0,len(data)) if list(data[i:i+len(pattern)])==pattern]\n",
    "\n",
    "def get_clocks(extclk=False, freq=None, oversamp=None):\n",
    "    done = False\n",
    "    count = 0\n",
    "    while not done and count < 30:\n",
    "        scope.LA.arm()\n",
    "        scope.LA.trigger_now()\n",
    "        raw = scope.LA.read_capture_data()\n",
    "        adcclock = scope.LA.extract(raw, 8)\n",
    "        if extclk:\n",
    "            refclock = scope.LA.extract(raw, 4)\n",
    "        else:\n",
    "            refclock = scope.LA.extract(raw, 5)\n",
    "        \n",
    "        edges = find0to1trans(refclock)\n",
    "        if len(edges) > 1:\n",
    "            ref_edge = edges[1]\n",
    "        else:\n",
    "            ref_edge = edges[0]    \n",
    "        \n",
    "        try:\n",
    "            if extclk:\n",
    "                # account for fixed offset when extclk: 10ns from *falling edge* of refclock to *rising edge* of adcclock\n",
    "                # we return the phase deviation from this 10ns, however we don't transform the raw clocks; they are returned as-is\n",
    "                if not freq or not oversamp:\n",
    "                    print('get_clocks() needs freq and oversamp when extclk is set!')\n",
    "                    return 0,0,0,0\n",
    "                # first, calculate the raw phase, in case it's interesting:\n",
    "                adc_edges = find0to1trans(adcclock)\n",
    "                adc_ref_delta2 = abs(min(adc_edges, key=lambda x:abs(x-ref_edge)) - ref_edge)\n",
    "                # then calculate against the fixed 10ns offset\n",
    "                edges = find0to1trans(refclock ^ 1) # get falling edge\n",
    "                ref_edge = edges[1]\n",
    "                # calculate 10ns in samples:\n",
    "                offset = round(10e-9/(1/freq/oversamp))\n",
    "                #print('offset=%d' % offset)\n",
    "                #adc_edges = list(np.asarray(find0to1trans(adcclock)) - offset)\n",
    "                #adc_ref_delta1 = abs(min(adc_edges, key=lambda x:abs(x-ref_edge)) - ref_edge)\n",
    "                adc_ref_delta1 = find0to1trans(adcclock[ref_edge+offset:])[0]\n",
    "                done = True\n",
    "\n",
    "            else:\n",
    "                adc_ref_delta1 = find0to1trans(adcclock[ref_edge:])[0]\n",
    "                adc_edges = find0to1trans(adcclock)\n",
    "                adc_ref_delta2 = abs(min(adc_edges, key=lambda x:abs(x-ref_edge)) - ref_edge)\n",
    "                done = True\n",
    "        except:\n",
    "            # not sure why but sometimes the ADC clock comes back all zeros; could be an issue with the PLL or with the LA?\n",
    "            # what's very strange is that this doesn't happen often, but when it does, adcclock is always all zeros, and \n",
    "            # the capture is re-attempted exactly 19 times before it's successful!\n",
    "            if all(c == 0 for c in adcclock):\n",
    "                adcclock = 'all zeros'\n",
    "            print('could not find delta; ref_edge=%3d, lock status=%s; adcclock=%s; trying again' % (ref_edge, scope.clock.pll.pll_locked, adcclock))\n",
    "            assert scope.LA.locked\n",
    "            assert scope.clock.pll.pll_locked\n",
    "            time.sleep(0.5)\n",
    "            count += 1\n",
    "            done = True # TEMP!\n",
    "    return adc_ref_delta1, adc_ref_delta2, adcclock, refclock"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd9b6cf1-08c2-448c-ae0f-01cb60e2e49a",
   "metadata": {},
   "source": [
    "# Phase Check\n",
    "\n",
    "Here we pick a random clock frequency, set `adc_mul = 1`, and check that the relative phase between the clocks is ~correct for all `scope.clock.adc_phase` values.\n",
    "\n",
    "When `EXTCLK=True`, this is difficult because the relative phase depends on the clock frequency. So we take one measurement, assume it is good, and apply an offset for all other measurements.\n",
    "\n",
    "The last section of this notebook, \"Sweep frequency with phase held at 0\", can be used to explore how the phase varies with the clock.\n",
    "\n",
    "We used to also test if the phase is monotonically increasing, but doing this *properly* is completely redundant."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54fcff1d-fbf1-4ee1-8b0f-ed5d67882cdd",
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trace.clock._warning_frequency = 303e6"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be322580-d9cd-442e-830c-4291ec4d6a48",
   "metadata": {},
   "outputs": [],
   "source": [
    "EXTCLK"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6ffa957f-46db-48dd-8a61-f007f9e540b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "#REPS = 100\n",
    "REPS = 1000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a1182fd-a272-4290-a59f-aa9bc09c4756",
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm.notebook import tnrange, tqdm\n",
    "import numpy as np\n",
    "import time\n",
    "import random\n",
    "\n",
    "freqmuls = []\n",
    "all_settings = []\n",
    "la_skipped = 0\n",
    "setup_skipped = 0\n",
    "fails = 0\n",
    "passes = 0\n",
    "all_diffs = []\n",
    "\n",
    "pbar = tqdm(total=REPS, desc='Passing')\n",
    "fbar = tqdm(total=REPS, desc='Failing')\n",
    "sbar = tqdm(total=REPS, desc='Skipped')\n",
    "\n",
    "for r in tnrange(REPS):\n",
    "    FREQ = random.randint(5e2, 20e2)*1e4 # lower resolution gets much faster setting of the CW305 PLL\n",
    "    OVERSAMP = int(300e6//FREQ)\n",
    "    samples = OVERSAMP*2\n",
    "    if EXTCLK:\n",
    "        # in this case, the ADC clock and target-generated clock can both be shifting around relative to each other, so we need to tolerate a larger deviance:\n",
    "        mintol = 3\n",
    "    else:\n",
    "        mintol = 2\n",
    "    TOL = max(mintol, OVERSAMP//30)\n",
    "    MUL = 1\n",
    "    freqmuls.append([FREQ, MUL])\n",
    "    try:\n",
    "        setup(FREQ, MUL, 0)\n",
    "        set_oversamp(OVERSAMP)\n",
    "        time.sleep(0.5)\n",
    "        if abs(scope.LA.sampling_clock_frequency/FREQ - OVERSAMP) / OVERSAMP * 100 > 1:\n",
    "            la_skipped += 1\n",
    "            sbar.update(1)\n",
    "            continue\n",
    "    except Exception as e:\n",
    "        print('failed to setup: %s' % e)\n",
    "        setup_skipped += 1\n",
    "        continue\n",
    "\n",
    "    # Now sweep over all raw phase steps, but don't go over one full clock period for speed and simplicity\n",
    "    # (this way we (should) end up with a strictly monotonically increasing relative phase).\n",
    "    # Note that often we cannot cover a full clock period!\n",
    "    if EXTCLK:\n",
    "        start_phase = 0\n",
    "        steps = min(32, scope.clock.pll.get_outdiv(3)) # 32 is the max range of phase adjustments (0 to +31)\n",
    "    else:\n",
    "        start_phase = -min(31, scope.clock.pll.get_outdiv(3))\n",
    "        steps = min(63, scope.clock.pll.get_outdiv(3)) # 63 is the max range of phase adjustments (-31 to +31)\n",
    "\n",
    "\n",
    "    measured_phases = []\n",
    "    adcs = []\n",
    "    refs = []\n",
    "\n",
    "    for phase_raw in range(start_phase, start_phase+steps):\n",
    "        scope.clock.adc_phase_raw = phase_raw\n",
    "        measured_phase, phase2, adc, ref = get_clocks(EXTCLK, FREQ, OVERSAMP)\n",
    "        settings = str(scope.clock.pll)\n",
    "        params = scope.clock.pll.parameters\n",
    "        sampling_clock = scope.LA.sampling_clock_frequency\n",
    "\n",
    "        offset = find0to1trans(ref)[0]\n",
    "        adcs.append(adc[offset:offset+samples])\n",
    "        refs.append(ref[offset:offset+samples])\n",
    "        measured_phases.append(measured_phase)\n",
    "\n",
    "        # compare measured phase against expected:\n",
    "        expected_measurement = OVERSAMP * scope.clock.adc_phase/100\n",
    "        # could be off by a full period:\n",
    "        diff = expected_measurement - measured_phase\n",
    "        diffs = [abs(diff), abs(diff+OVERSAMP), abs(diff-OVERSAMP)]\n",
    "        all_diffs.append(min(diffs))\n",
    "        if min(diffs) > TOL:\n",
    "            print('FAIL! freq=%d, oversamp=%d, phase_raw=%d, diffs=%s' % (FREQ, OVERSAMP, phase_raw, diffs))\n",
    "            fails += 1\n",
    "            fbar.update(1)\n",
    "        else:\n",
    "            passes += 1\n",
    "            pbar.update(1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "925a7427-cbd0-418a-9a59-2370b46a5300",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert fails == 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dfd9a445-18d0-4c0a-9286-428aadb5c615",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert passes/(la_skipped+setup_skipped) > 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0612c53c-1350-410f-8ab6-d2c01bd3f49c",
   "metadata": {},
   "outputs": [],
   "source": [
    "la_skipped, setup_skipped"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0a63017-1705-461f-8013-49ac5ff02f8e",
   "metadata": {},
   "source": [
    "**This concludes the test; the rest of this notebook is to help diagnose failures.**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63296dee-8c93-4c1e-8f0a-d31afa186e0a",
   "metadata": {},
   "source": [
    "## replicate a failure:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "10b8d265-4944-48aa-9680-919aec04bab4",
   "metadata": {},
   "outputs": [],
   "source": [
    "#FREQ = freqmuls[0][0]\n",
    "#FREQ = 5e6\n",
    "#FREQ = 10e6\n",
    "FREQ = 20e6\n",
    "#FREQ = 5130000\n",
    "\n",
    "MUL = 1\n",
    "\n",
    "setup(FREQ, MUL, 0)\n",
    "OVERSAMP = int(300e6//FREQ)\n",
    "set_oversamp(OVERSAMP)\n",
    "samples = OVERSAMP*2\n",
    "\n",
    "scope.clock.adc_phase_raw = 0\n",
    "measured_phase, phase2, adc, ref = get_clocks(EXTCLK, FREQ, OVERSAMP)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9adbb25b-3a2b-4731-95a1-e722dcb24c4f",
   "metadata": {},
   "outputs": [],
   "source": [
    "expected_measurement = OVERSAMP * scope.clock.adc_phase/100\n",
    "# could be off by a full period:\n",
    "diff = expected_measurement-measured_phase\n",
    "diffs = [abs(diff), abs(diff+OVERSAMP)]\n",
    "all_diffs.append(min(diffs))\n",
    "if min(diffs) > TOL:\n",
    "    print('FAIL! freq=%d, oversamp=%d, phase_raw=%d, diff=%d' % (FREQ, OVERSAMP, phase_raw, min(diffs)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cbaaeef4-ac3d-49bb-9354-cbd94fad6ce3",
   "metadata": {},
   "outputs": [],
   "source": [
    "if EXTCLK:\n",
    "    start_phase = 0\n",
    "    steps = min(32, scope.clock.pll.get_outdiv(3)) # 32 is the max range of phase adjustments (0 to +31)\n",
    "else:\n",
    "    start_phase = -min(31, scope.clock.pll.get_outdiv(3))\n",
    "    steps = min(63, scope.clock.pll.get_outdiv(3)) # 63 is the max range of phase adjustments (-31 to +31)\n",
    "\n",
    "measured_phases = []\n",
    "measured_phases2 = []\n",
    "adcs = []\n",
    "refs = []\n",
    "\n",
    "for phase_raw in tnrange(start_phase, start_phase+steps):\n",
    "    scope.clock.adc_phase_raw = phase_raw\n",
    "    measured_phase, phase2, adc, ref = get_clocks(EXTCLK, FREQ, OVERSAMP)\n",
    "    settings = str(scope.clock.pll)\n",
    "    params = scope.clock.pll.parameters\n",
    "    sampling_clock = scope.LA.sampling_clock_frequency\n",
    "\n",
    "    offset = find0to1trans(ref)[0]\n",
    "    adcs.append(adc[offset:offset+samples])\n",
    "    refs.append(ref[offset:offset+samples])\n",
    "    measured_phases.append(measured_phase)\n",
    "    measured_phases2.append(phase2)\n",
    "\n",
    "    # compare measured phase against expected:\n",
    "    expected_measurement = OVERSAMP * scope.clock.adc_phase/100\n",
    "    # could be off by a full period:\n",
    "    diff = expected_measurement - measured_phase\n",
    "    diffs = [abs(diff), abs(diff+OVERSAMP), abs(diff-OVERSAMP)]\n",
    "    all_diffs.append(min(diffs))\n",
    "    if min(diffs) > TOL:\n",
    "        print('FAIL! freq=%d, oversamp=%d, phase_raw=%d, diffs=%s' % (FREQ, OVERSAMP, phase_raw, diffs))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca3224b8-5350-4bcb-af31-c6258db6924f",
   "metadata": {},
   "source": [
    "## visualize phase monotonicity:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "78b83eff-7c43-4b7c-b78e-7b8ae435c95e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.resources import INLINE\n",
    "from bokeh.io import output_notebook\n",
    "\n",
    "output_notebook(INLINE)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5a135fc8-2fe6-45ec-8c30-3bf5bfd8dee2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# test if monotonically increasing (with a shift allowed)\n",
    "# won't work if we capture more than one period!\n",
    "reordered_phases = []\n",
    "reorder = None\n",
    "for i in range(1,len(measured_phases)):\n",
    "    #if measured_phases[i] < measured_phases[i-1]:\n",
    "    if measured_phases[i] < measured_phases[i-1] - OVERSAMP//2:\n",
    "        reorder = i\n",
    "if reorder:\n",
    "    reordered_phases = measured_phases[reorder:] +  measured_phases[:reorder]\n",
    "else:\n",
    "    reordered_phases = measured_phases\n",
    "\n",
    "TOL = 1\n",
    "for i in range(1,len(reordered_phases)):\n",
    "    if reordered_phases[i] + TOL < reordered_phases[i-1]:\n",
    "        print('FAIL! i=%d' % i)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d595705-8c2b-4525-a662-3a3572b47f05",
   "metadata": {},
   "outputs": [],
   "source": [
    "xrange = list(range(len(measured_phases)))\n",
    "p = figure(width=1800)\n",
    "p.line(xrange, measured_phases, line_color='green')\n",
    "#p.line(xrange, measured_phases2, line_color='red')\n",
    "p.line(xrange, reordered_phases, line_color='blue')\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf8795a6-428f-418d-8be0-9ad8310f0a68",
   "metadata": {},
   "outputs": [],
   "source": [
    "def update_plot(p):\n",
    "    S1.data_source.data['y'] = refs[p][:samples] + 2\n",
    "    S2.data_source.data['y'] = adcs[p][:samples] + 0  \n",
    "    push_notebook()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "72882196-d1e1-439a-9fb8-9829abb44b70",
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import interact, Layout\n",
    "from bokeh.io import push_notebook\n",
    "from bokeh.models import Span, Legend, LegendItem\n",
    "\n",
    "p = 0\n",
    "\n",
    "S = figure(width=1800)\n",
    "\n",
    "samples = int(OVERSAMP*2)\n",
    "xrange = list(range(samples))\n",
    "\n",
    "S1 = S.line(xrange, refs[p][:samples] + 2, line_color='black')\n",
    "S2 = S.line(xrange, adcs[p][:samples] + 0, line_color='blue')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b61e4adc-1227-4e10-a83d-3b9ff9a6a8f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "show(S, notebook_handle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f62a614-bc31-49f6-b956-87769b4a8b50",
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(update_plot, p=(0, len(adcs)-1))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ed752be-9ba6-4c86-a06a-42285a290e9b",
   "metadata": {},
   "source": [
    "## Sweep frequency with phase held at 0:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "51b4058a-845d-4ad7-90c8-008b6d09ed51",
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.LA.capture_depth = 500"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c4381447-ce4e-4960-8ae6-74764fd2ddcd",
   "metadata": {},
   "outputs": [],
   "source": [
    "samples = 300e6//5e6*4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e87ea00-7a41-4e7f-8dd6-cf2faf8d8ece",
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.userio.mode = 'fpga_debug'\n",
    "scope.userio.fpga_mode = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3ae96ab-b32d-4485-a6b6-28842f6bced3",
   "metadata": {},
   "outputs": [],
   "source": [
    "all_settings = []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f54b98c-2af2-40af-b3af-2f5bc4adaf2f",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from tqdm.notebook import tnrange, tqdm\n",
    "import numpy as np\n",
    "import time\n",
    "import random\n",
    "\n",
    "measured_phases = []\n",
    "measured_phases2 = []\n",
    "adcs = []\n",
    "refs = []\n",
    "all_settings = []\n",
    "samples = None\n",
    "\n",
    "for FREQ in tnrange(int(5e6), int(30e6), int(2e5)):\n",
    "    MUL = 1\n",
    "    setup(FREQ, MUL, 0)\n",
    "    OVERSAMP = int(300e6//FREQ)\n",
    "    set_oversamp(OVERSAMP)\n",
    "    if samples is None:\n",
    "        samples = OVERSAMP*4\n",
    "    \n",
    "    scope.clock.adc_phase_raw = 0\n",
    "    measured_phase, phase2, adc, ref = get_clocks(EXTCLK, FREQ, OVERSAMP)\n",
    "\n",
    "    offset = find0to1trans(ref)[0]\n",
    "    adcs.append(adc[offset:offset+samples])\n",
    "    refs.append(ref[offset:offset+samples])\n",
    "    measured_phases.append(measured_phase)\n",
    "    measured_phases2.append(phase2)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f9b3fc6b-7d32-4d88-bc2b-9df4ef65e1ae",
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.resources import INLINE\n",
    "from bokeh.io import output_notebook\n",
    "\n",
    "output_notebook(INLINE)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "842f1a6c-b297-48ce-bc9d-46385fdb0f67",
   "metadata": {},
   "outputs": [],
   "source": [
    "xrange = list(range(len(measured_phases)))\n",
    "p = figure(width=1800)\n",
    "p.line(xrange, measured_phases, line_color='green')\n",
    "#p.line(xrange, measured_phases2, line_color='blue')\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d38a4e0-109d-4ae4-b601-338c24687999",
   "metadata": {},
   "outputs": [],
   "source": [
    "def update_plot(f):\n",
    "    S1.data_source.data['y'] = refs[f][:samples] + 2\n",
    "    S2.data_source.data['y'] = adcs[f][:samples] + 0  \n",
    "    push_notebook()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48cbfdbf-9bf6-4f82-a451-c7a1223be34b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import interact, Layout\n",
    "from bokeh.io import push_notebook\n",
    "from bokeh.models import Span, Legend, LegendItem\n",
    "\n",
    "p = 0\n",
    "\n",
    "S = figure(width=1800)\n",
    "\n",
    "samples = 80\n",
    "xrange = list(range(samples))\n",
    "\n",
    "S1 = S.line(xrange, refs[p][:samples] + 2, line_color='black')\n",
    "S2 = S.line(xrange, adcs[p][:samples] + 0, line_color='blue')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "121d0da3-2c8a-4f3d-8197-846194c00601",
   "metadata": {},
   "outputs": [],
   "source": [
    "show(S, notebook_handle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d5d5699-f62a-4ca8-ad96-d7b11b025468",
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(update_plot, f=(0, len(adcs)-1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d53334b-a5bb-4bda-b1c4-e05eb9360b11",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (venv39)",
   "language": "python",
   "name": "venv39"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
